﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace Examples.CAMLFilter
{
    [ToolboxItemAttribute(false)]
    public class CAMLFilterForm : WebPart
    {

        const String idClearAllFields = "btnClearAllFields";


        /// <summary>
        /// Текущая локаль
        /// </summary>
        private Locale locale = new Locale();

        #region Параметры веб-части, которые редактируются через FilterEditor

        /// <summary>
        /// Количество столбцов в форме
        /// </summary>
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public int FormColumns { get; set; }
        private int columns { get { return FormColumns > 0 ? FormColumns : 1; } }


        /// <summary>
        /// Ширина текста
        /// </summary>
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public int TextWidth { get; set; }
        private int textWidth { get { return (TextWidth > 50 && TextWidth < 1000) ? TextWidth : 150; } }



        /// <summary>
        /// Как передаем параметры в фильтр
        /// </summary>
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public ValueSource Method { get; set; }

        /// <summary>
        /// Показывать подсказки в форме
        /// </summary>
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public Boolean ShowConditions { get; set; }

        /// <summary>
        /// Использовать cookies для хранения данных формы
        /// </summary>
        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public Boolean UseCookies { get; set; }

        #endregion Параметры веб-части, которые редактируются через FilterEditor



        /// <summary>
        /// Коллекция контролов для фильтров
        /// </summary>
        List<FieldControl> controls = new List<FieldControl>();

        /// <summary>
        /// Ссылка на связанную веб-часть
        /// </summary>
        CAMLFilter camlFilter;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            // Если вошли в режим редактирования - отключаем ViewState: при выходе наверняка контролы будут другие
            if (WebPartManager != null && WebPartManager.DisplayMode != WebPartManager.BrowseDisplayMode)
                EnableViewState = false;
        }


        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            EnsureChildControls();

            // Здесь восстановим данные из кук, если включено
            if (!Page.IsPostBack && this.UseCookies)
                foreach (FieldControl control in controls)
                    control.Input.Value = HttpContext.Current.Request.Cookies[control.CookieName] == null ? null : HttpContext.Current.Request.Cookies[control.CookieName].Value;

            // Проверим - если передавали какие-нибудь значения для фильтров через реквест - очистим старые и заполним новыми
            Boolean resetValues = false;

            foreach (FieldControl control in controls)
                if (HttpContext.Current.Request.Params[control.Filter.Value] != null)
                {
                    resetValues = true;
                    break;
                }

            if (resetValues)
                foreach (FieldControl control in controls)
                    control.Input.Value = HttpContext.Current.Request.Params[control.Filter.Value];

        }


        protected override void CreateChildControls()
        {

            base.CreateChildControls();

            // Здесь создаем статические контролы
            Panel pMain = new Panel();
            pMain.Style.Add("padding", "5px;");

            this.Controls.Add(pMain);

            UpdatePanel upWork = new UpdatePanel() { ID = "upWork", UpdateMode = UpdatePanelUpdateMode.Conditional };

            pMain.Controls.Add(upWork);

            try
            {

                // Берем связанную веб-часть
                if (this.WebPartManager != null)
                    foreach (WebPartConnection conn in this.WebPartManager.Connections)
                    {
                        if (conn.Consumer == this && this.WebPartManager.WebParts[conn.ProviderID] is CAMLFilter)
                        {
                            camlFilter = this.WebPartManager.WebParts[conn.ProviderID] as CAMLFilter;
                            break;
                        }
                    }

                if (camlFilter == null) throw new Exception(SPUtility.GetLocalizedString("$Resources:ErrFormNotConnected", "Examples.CAMLFilter", locale));


                // Если нет Id - значит, еще не сконфигурили веб-часть фильтра
                if (camlFilter.ListId == Guid.Empty) return;

                SPList list = SPContext.Current.Web.Lists[camlFilter.ListId];

                // Пробегаем по всем фильтрам и выбираем те, с которыми работаем

                if (camlFilter.Filters != null)
                {
                    int i = 0;
                    foreach (Filter filter in camlFilter.Filters)
                    {
                        // Берем только активные и только с типом источника Request
                        if (!filter.IsActive || filter.Source != ValueSource.Request) continue;

                        FieldControl control = new FieldControl(filter, list.Fields.GetFieldByInternalName(filter.FieldName), locale, textWidth, i);
                        controls.Add(control);
                        i++;
                    }
                }

                List<String> inputIds = new List<String>();

                if (controls.Count > 0)
                {
                    // Теперь генерим таблицу
                    Table tForm = new Table() { CellPadding = 0 };

                    upWork.ContentTemplateContainer.Controls.Add(tForm);

                    int nRows = (controls.Count / columns) + (controls.Count % columns != 0 ? 1 : 0);
                    TableCell cTitle;
                    TableCell cCondition;
                    TableCell cControl;
                    for (int i = 0; i < nRows; i++)
                    {
                        TableRow row = new TableRow();
                        tForm.Rows.Add(row);

                        for (int j = 0; j < columns; j++)
                        {
                            cTitle = new TableCell(); // { VerticalAlign = VerticalAlign.Top };
                            cTitle.Style.Add("padding-top", "3px;");
                            cTitle.Style.Add("padding-left", "10px;");
                            cTitle.Style.Add("padding-right", "3px;");
                            cTitle.Style.Add("padding-bottom", "3px;");
                            cTitle.Style.Add("white-space", "nowrap;");


                            cCondition = new TableCell(); // { VerticalAlign = VerticalAlign.Top };
                            cCondition.Style.Add("padding-top", "3px;");
                            cCondition.Style.Add("padding-left", "3px;");
                            cCondition.Style.Add("padding-right", "3px;");
                            cCondition.Style.Add("padding-bottom", "3px;");
                            cCondition.Style.Add("white-space", "nowrap;");

                            cControl = new TableCell(); // { VerticalAlign = VerticalAlign.Top };
                            cControl.Style.Add("padding-top", "3px;");
                            cControl.Style.Add("padding-left", "3px;");
                            cControl.Style.Add("padding-right", "10px;");
                            cControl.Style.Add("padding-bottom", "3px;");
                            cControl.Style.Add("white-space", "nowrap;");


                            int idx = (j * nRows) + i;
                            if (idx < controls.Count)
                            {
                                Label lTitle = new Label() { Text = controls[idx].Title };
                                if (this.ShowConditions) lTitle.Font.Bold = true;
                                cTitle.Controls.Add(lTitle);
                                if (this.ShowConditions) cCondition.Controls.Add(new LiteralControl(SPUtility.GetLocalizedString("$Resources:Condition" + controls[idx].Filter.Condition.ToString(), "Examples.CAMLFilter", locale).ToLower()));
                                cControl.Controls.Add(controls[idx].Input);
                            }
                            else
                            {
                                cTitle.Controls.Add(new LiteralControl("&nbsp;"));
                                if (this.ShowConditions) cCondition.Controls.Add(new LiteralControl("&nbsp;"));
                                cControl.Controls.Add(new LiteralControl("&nbsp;"));
                            }
                            row.Cells.Add(cTitle);
                            if (this.ShowConditions) row.Cells.Add(cCondition);
                            row.Cells.Add(cControl);

                            // Надо создать дочерние контролы после того, как добавили папу в таблицу, чтобы правильно прописались их ClientIds
                            if (idx < controls.Count) controls[idx].Input.EnsureControls();

                        }

                    }


                    // Панель для кнопок
                    Panel pButtons = new Panel();
                    pButtons.Style.Add("padding-top", "3px;");
                    pButtons.Style.Add("padding-left", "10px;");
                    pButtons.Style.Add("padding-right", "3px;");
                    pButtons.Style.Add("padding-bottom", "3px;");
                    pButtons.Style.Add("white-space", "nowrap;");


                    LinkButton btnSearch = new LinkButton() { ID = "btnSearch", Text = SPUtility.GetLocalizedString("$Resources:WPFSearch", "Examples.CAMLFilter", locale) };
                    btnSearch.Click += new EventHandler(btnSearch_Click);
                    pButtons.Controls.Add(btnSearch);

                    pButtons.Controls.Add(new LiteralControl() { Text = "&nbsp;&nbsp;|&nbsp;&nbsp;" });

                    LinkButton btnClearAll = new LinkButton() { ID = idClearAllFields, Text = SPUtility.GetLocalizedString("$Resources:WPFClearAllFields", "Examples.CAMLFilter", locale) };
                    btnClearAll.Click += new EventHandler(btnSearch_Click);
                    pButtons.Controls.Add(btnClearAll);

                    // Если у нас включен метод POST - добавляем за пределами UpdatePanel, пока не научимся делать
                    // глобальные постбэки изнутри нее
                    if (this.Method == ValueSource.Form)
                        pMain.Controls.Add(pButtons);
                    else
                        upWork.ContentTemplateContainer.Controls.Add(pButtons);



                }

            }
            catch (Exception ex)
            {
                pMain.Controls.Clear();
                pMain.Controls.Add(new LiteralControl(String.Format(SPUtility.GetLocalizedString("$Resources:ErrorPrompt", "Examples.CAMLFilter", locale), ex.Message) + "<br/>"));
            }

        }


        #region Event handlers


        void btnSearch_Click(object sender, EventArgs e)
        {

            // Кнопка сброса всех условий?
            Boolean clearValues = (sender is LinkButton) && (idClearAllFields.Equals((((LinkButton)sender).ID)));

            if (!Page.IsValid && !clearValues) return;

            // Пробегаем по всем контролам и формируем запрос на поиск

            List<String> values = new List<String>();
            foreach (FieldControl control in controls)
            {
                // Если нажали на очистку - очищаем значения
                if (clearValues) control.Input.Value = null;

                String value = control.Input.Value;

                // Сохраняем значения, если надо
                if (this.UseCookies)
                {
                    HttpCookie c = new HttpCookie(control.CookieName, value);
                    c.Expires = String.IsNullOrEmpty(value) ? DateTime.MinValue : DateTime.Now.AddYears(1);
                    System.Web.HttpContext.Current.Response.Cookies.Add(c);
                }


                // Skip non-used controls
                if (String.IsNullOrEmpty(value)) continue;

                if (this.Method == ValueSource.Form)
                    values.Add(String.Format("<input type='hidden' name='{0}' value='{1}'>", control.Filter.Value, SPEncode.HtmlEncode(value)));
                else
                    values.Add(String.Format("{0}={1}", control.Filter.Value, value.Replace(" ", "%20").Replace("?", "%3F").Replace("&", "%26").Replace("=", "%3D")));

            }



            if (this.Method == ValueSource.Form)
            {

                // POST-запрос
                StringBuilder response = new System.Text.StringBuilder();

                HttpContext.Current.Response.Clear();
                response.Append("<html>");
                response.AppendFormat("<body onload='document.forms[0].submit()'>");
                response.AppendFormat("<form action='{0}' method='post'>", HttpContext.Current.Request.Url.AbsolutePath);
                response.AppendFormat(String.Join("", values.ToArray()));
                response.Append("</form>");
                response.Append("</body>");
                response.Append("</html>");

                HttpContext.Current.Response.Write(response.ToString());
                HttpContext.Current.Response.End();
            }
            else
            {
                // GET-редирект
                StringBuilder response = new System.Text.StringBuilder();

                HttpContext.Current.Response.Clear();
                response.AppendFormat("{0}?", HttpContext.Current.Request.Url.AbsolutePath);
                response.AppendFormat(String.Join("&", values.ToArray()));
                System.Web.HttpContext.Current.Response.Redirect(response.ToString());
            }




        }

        #endregion Event handlers

        #region ICAMLFilter consumer implementation

        // Он нам нужен только для связи веб-частей, реально данные передаваться не будут
        [ConnectionConsumer("CAML Filters", "CAMLFilterConsumer")]
        public void ICAMLFilterConsumer(ICAMLFilter provider)
        {
        }

        #endregion

        // Добавляем свой контрол для редактирования вебчастей
        public override EditorPartCollection CreateEditorParts()
        {
            ArrayList editorParts = new ArrayList();
            editorParts.Add(
                new FormEditor()
                {
                    Title = SPUtility.GetLocalizedString("$Resources:WPFormEditorTitle", "Examples.CAMLFilter", locale),
                    ID = this.ID + "_FormEditor"
                }
            );
            return new EditorPartCollection(editorParts);
        }


    }

}
